#include <iostream>

// 多态
// 静态多态
// 编译阶段确定函数地址
// 函数重载、运算符重载


// 动态多态
// 运行阶段确定函数地址
// 派生类和虚函数
// 满足条件：有继承关系，子类重写父类的虚函数
// 使用：父类的指针或者引用指向子类的对象
class animal{
public:
    //虚函数
    // animal类中维护了一个虚函数指针vfptr，vfptr指向vftable中的函数地址，也就是子类的成员函数地址
    // 当子类没有重写父类成员函数时，子类就全部继承了父类的成员，也就是说vftable中记录的是父类中成员函数的地址
    virtual void func(){    //虚函数
        std::cout<< "animal"<< std::endl;
    }
};
class cat: public animal{
public:
    void func(){
        std::cout<< "cat"<< std::endl;
    }
};

// 向上转型，允许父类与子类之间进行类型转换
// 引用指向子类的对象
void printFunc(animal &animal){  //animal &animal = c    
    animal.func();
}
void test01(){
    cat c;
    printFunc(c);
}


// 纯虚函数
// 当类中有了纯虚函数，这个类也叫抽象类
// 抽象类
// 无法实例化对象
// 子类必须重写抽象类中的纯虚函数，否则子类也属于抽象类

// 案例：计算器：
class Calculator{   // 抽象类
public:
    int numA;
    int numB;
    virtual int getResult() = 0;    // 纯虚函数
       
};
class Add : public Calculator{
public:

    int getResult(){
        return numA + numB;
    }
};
class subtract : public Calculator{
public:
    int getResult(){
        return numA - numB;
    }
};

void test02(){
    Calculator *c = new Add();
    c->numA = 10;
    c->numB = 20;
    std::cout<< c->getResult() <<std::endl;
    delete c;

    c = new subtract();
    c->numA = 10;
    c->numB = 20;
    std::cout<< c->getResult() <<std::endl;
    delete c;
}

// 虚析构和纯虚析构
// 在多态使用中，如果有子类中有属性开辟到堆区，那么父类指针在释放时无法调用到子类的析构代码
// 解决方法：在父类的析构函数改为虚析构或纯虚析构
// 可以解决父类指针释放子类对象
// 都需要有具体的函数实现
class Home{
public:

    Home(){
        std::cout<< "Home 构造"<<std::endl;
    }

    // virtual ~Home(){    // 虚析构
    //     std::cout<< "Home 析构"<<std::endl;
    // }

    // 必须要有类外实现，否则会报错
    // 因为父类中也有可能会有需要析构的成员变量
    virtual ~Home() = 0;    //纯虚析构

    virtual void owned() = 0;   //纯虚函数
};
Home::~Home(){
    std::cout<< "Home 析构"<<std::endl;
}

class man : public Home {
public:

    std::string *name;

    man(std::string s){
        std::cout<< "man 构造"<<std::endl;
        this->name = new std::string(s);
    }
    ~man(){
        std::cout<< "man 析构"<<std::endl;
        if(this->name != NULL){
            delete this->name;
        }
        this->name = NULL;
    }

    void owned(){
        std::cout<< *name <<" owned"<<std::endl;
    }

};
void test03(){
    Home *home = new man("wan");
    home->owned();
    // 父类指针在析构的时候，不会调用子类中的析构函数，导致子类如果有堆区数据，会出现内存泄漏
    delete home;
}

int main()
{
    // test01();
    // test02();
    test03();
    return 0;
}